import tkinter as tk
from tkinter import ttk, messagebox
from protocol import pack_query_cmd, pack_set_cmd, parse_set_response, parse_query_response


class ParamPresetFrame(ttk.LabelFrame):
    def __init__(self, master, serial_comm, obj_name, obj_code):
        super().__init__(master, text=f"参数预设 - {obj_name}")
        self.serial_comm = serial_comm
        self.obj_code = obj_code
        self.log_callback = None  # 日志回调函数
        self._build_ui()

    def _build_ui(self):
        self.mode_var = tk.StringVar(value="扫描")
        self.ampl_var = tk.IntVar(value=0)
        self.start_var = tk.IntVar(value=0)
        self.end_var = tk.IntVar(value=0)
        self.rate_var = tk.IntVar(value=300)
        self.step_var = tk.IntVar(value=100)
        row = 0
        ttk.Label(self, text="工作方式:").grid(row=row, column=0, padx=5, pady=5)
        self.mode_combo = ttk.Combobox(self, textvariable=self.mode_var, values=["扫描", "定值"], width=8,
                                       state="readonly")
        self.mode_combo.grid(row=row, column=1, padx=5, pady=5)
        self.ampl_label = ttk.Label(self, text="幅值(mV):")
        self.ampl_label.grid(row=row, column=2, padx=5, pady=5)
        self.ampl_entry = ttk.Entry(self, textvariable=self.ampl_var, width=8)
        self.ampl_entry.grid(row=row, column=3, padx=5, pady=5)
        row += 1
        self.start_label = ttk.Label(self, text="起始值(mV):")
        self.start_label.grid(row=row, column=0, padx=5, pady=5)
        self.start_entry = ttk.Entry(self, textvariable=self.start_var, width=8)
        self.start_entry.grid(row=row, column=1, padx=5, pady=5)
        self.end_label = ttk.Label(self, text="终止值(mV):")
        self.end_label.grid(row=row, column=2, padx=5, pady=5)
        self.end_entry = ttk.Entry(self, textvariable=self.end_var, width=8)
        self.end_entry.grid(row=row, column=3, padx=5, pady=5)
        row += 1
        self.rate_label = ttk.Label(self, text="扫描速率(ms):")
        self.rate_label.grid(row=row, column=2, padx=5, pady=5)
        self.rate_entry = ttk.Entry(self, textvariable=self.rate_var, width=8)
        self.rate_entry.grid(row=row, column=3, padx=5, pady=5)
        self.step_label = ttk.Label(self, text="扫描步进(mV):")
        self.step_label.grid(row=row, column=0, padx=5, pady=5)
        self.step_entry = ttk.Entry(self, textvariable=self.step_var, width=8)
        self.step_entry.grid(row=row, column=1, padx=5, pady=5)
        row += 1

        self.query_btn = ttk.Button(self, text="查询", command=self.query_param)
        self.query_btn.grid(row=row, column=2, padx=5, pady=5)
        self.set_btn = ttk.Button(self, text="设置", command=self.set_param)
        self.set_btn.grid(row=row, column=3, padx=5, pady=5)

        # 绑定模式变化回调
        self.mode_var.trace_add('write', self._on_mode_change)
        self._on_mode_change()

    def _on_mode_change(self, *args):
        mode = self.mode_var.get()
        if mode == "扫描":
            self.ampl_label.grid_remove()
            self.ampl_entry.grid_remove()
            self.start_label.grid()
            self.start_entry.grid()
            self.end_label.grid()
            self.end_entry.grid()
            self.rate_label.grid()
            self.rate_entry.grid()
            self.step_label.grid()
            self.step_entry.grid()
        else:
            self.ampl_label.grid()
            self.ampl_entry.grid()
            self.start_label.grid_remove()
            self.start_entry.grid_remove()
            self.end_label.grid_remove()
            self.end_entry.grid_remove()
            self.rate_label.grid_remove()
            self.rate_entry.grid_remove()
            self.step_label.grid_remove()
            self.step_entry.grid_remove()

    def set_mode(self, mode):
        """外部调用，强制切换模式"""
        self.mode_var.set(mode)

    def query_param(self):
        try:
            cmd = pack_set_cmd(self.obj_code)
            self.log_serial_send(cmd)
            self.serial_comm.send(cmd)
            data = self.serial_comm.receive()

            self.log_serial_receive(data)
            resp = parse_set_response(data)
            if resp:
                self.mode_var.set("扫描" if resp['mode'] == 1 else "定值")
                self.ampl_var.set(resp['vo'])
                self.start_var.set(resp['vs'])
                self.end_var.set(resp['ve'])
                self.rate_var.set(resp['t'])
                self.step_var.set(resp['v'])
                self.add_log("参数查询成功", "INFO")
            else:
                self.add_log("查询失败", "ERROR")
                show_toast(self, "查询失败", 2000)
        except Exception as e:
            self.add_log(f"查询异常: {str(e)}", "ERROR")
            show_toast(self, f"查询异常: {str(e)}", 2000)

    def set_param(self):
        try:
            mode = 1 if self.mode_var.get() == "扫描" else 2
            vo = int(self.ampl_var.get())
            vs = int(self.start_var.get())
            ve = int(self.end_var.get())

            t = int(self.rate_var.get())
            v = int(self.step_var.get())
            # 校验
            vS = -15000
            vE = 15000
            if not (vS <= vo <= vE):
                raise ValueError(f"幅值范围{vS}到{vE}")
            if not (vS <= vs <= vE):
                raise ValueError(f"起始值范围{vS}到{vE}")
            if not (vS <= ve <= vE):
                raise ValueError(f"终止值范围{vS}到{vE}")
            if not (10 <= t <= 4000):
                raise ValueError("扫描速率范围10-4000")
            if not (100 <= v <= 2000):
                raise ValueError("扫描步进范围100-2000")
            cmd = pack_query_cmd(self.obj_code, mode, vo, vs, ve, t, v)
            self.log_serial_send(cmd)
            self.serial_comm.send(cmd)
            data = self.serial_comm.receive()
            self.log_serial_receive(data)
            resp = parse_query_response(data)
            if resp and resp['status'] == 1:
                self.add_log("参数设置成功", "INFO")
                show_toast(self, "设置成功", 2000)
            else:
                self.add_log("设置失败", "ERROR")
                show_toast(self, "设置失败", 2000)
        except Exception as e:
            self.add_log(f"设置异常: {str(e)}", "ERROR")
            show_toast(self, str(e), 2000)
    
    def set_log_callback(self, callback):
        """设置日志回调函数"""
        self.log_callback = callback
    
    def add_log(self, message, log_type="INFO"):
        """添加日志信息"""
        if self.log_callback:
            # 从标题中提取模块名称
            module_name = self.cget("text").replace("参数预设 - ", "") + "参数"
            self.log_callback(message, log_type, module_name)
    
    def log_serial_send(self, data):
        """记录串口发送数据"""
        self.add_log(f"发送: {data.hex()}", "SEND")
    
    def log_serial_receive(self, data):
        """记录串口接收数据"""
        self.add_log(f"接收: {data.hex()}", "RECV")


def show_toast(master, msg, duration=2000):
    toast = tk.Toplevel(master)
    toast.overrideredirect(True)
    toast.attributes("-topmost", True)
    label = tk.Label(toast, text=msg, bg="#333", fg="white", padx=20, pady=10, font=("微软雅黑", 12))
    label.pack()
    toast.update_idletasks()
    x = master.winfo_rootx() + (master.winfo_width() - toast.winfo_width()) // 2
    y = master.winfo_rooty() + (master.winfo_height() - toast.winfo_height()) // 2
    toast.geometry(f"+{x}+{y}")
    toast.after(duration, toast.destroy)
